About NodeJS

NodeJS is neither a language or a framework, it is more akin to a runtime engine that allows web pages to be served up from a server. The reason that NodeJS is popular is because it is fast, scalable, and is asynchronous, which means that the program can do other tasks while Node runs.

Required Software

Tutorial

NodeJS

To start off with we declare the contstants called http, port, url, and fs. For http, url, and fs we just make them equal to a require function in which we are passing those types. So for const http we are making that variable hold require('http').

const http = require('http'); const url = require("url"); const fs = require("fs");

For the port constant we just write which port we are going to be using for this.

const port = process.env.PORT || 1337;

We then have to create the server, in order to do that we initiate a variable, in our project it was called server, and we hold a function called http.CreateServer in which we execute an anonymous function that holds a request and a response. The request is what we are recieving and the response is what we are passing and writing to.

let server = http.createServer(function (req, res) { }

The https.createServer is what will hold the rest of our code. In order to make our life easier we create a varible called path that just holds what file is being requested.

let path = url.parse(req.url).pathname;

We then write a function inside of the fs.ReadFile() function in which we check for whether we got the file with success or not. If there was an error that happened, then we write the error to the the response that we said. If you are running node from the command line then the error will also pop up there. If it is a succcess then we write to the head 200 (which means success) and the content type that we are sending. For html the content type would be html, if it was javascript then it would be javascript, and if we are writing css then that would be css.

if (req.url.indexOf('.html') != -1) { fs.readFile(__dirname + '/' + path, function (error, data) { //If error is returned then write 404 and print out error message in command promp(Where we start server) if (error) { res.writeHead(404); res.write(error); res.end(); } else { //Writes the html content to the page res.writeHead(200, { 'Content-Type': 'text/html' }); res.write(data); res.end(); } }); }

Just repeat for javascript and css except replace any instance of 'html' with 'js' or 'css'. Once that is done then we have to make sure that the server will continue to listen to incoming requests. Whatever name you gave the variable that holds the http.createServer function write that variableName.list(port);

server.listen(port);

Database Tables

We have to create Hotel, HotelOrder, Flight, and FlightOrder tables for our website. Gain access to a server and and a database in which you can make these tables. In Visual Studio 2017 we go to the SQL Server Object Explorer and find the database that has been assigned to you, go to the tables folder, right click, then click on create table. This will bring up the designer view. First make the Flights table like this:

Then right click on the update button on the upper left corner of the designer view. Then right click on the Flights table and go into data view and insert this table:

Then create a new table called Hotels and design the table like this:

Then insert this data:

For the next two tables we will not be inserting any data since we will be inserting the table on the website. First create a new table called FlightOrder and design it like this:

Then create a new table called HotelOrder and design it like this:

API

Next we are going to create the DestinationAPI which will allows us to communicate to the database and the json file that we will create here. First right click on your solution, add new, new project, ASP.Net Core, API. Then right click on the Controller folder, add new, controller, new empty API. Then in that file change ControllerBase to just Controller. We will now add some newget packages. Right click on the API project, right click on manage newget packages, and make sure to install these packages:

Then go to Startup.cs and add this code to the ConfigureServices method:

services.AddCors(options => { options.AddPolicy("Access-Control-Allow-Origin", builder => { builder.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); });

Then in the Configure method add this line of code to the file:

app.UseCors("Access-Control-Allow-Origin");

Then we are going to add a .json file to the API project. Right click on the api project, add new, new file, .json file. Name that file stateInfo and we are going to add a json array that will hold json objects. Each object will hold the name of the state, description, and an image of the state. We are going to add all 50 states of the United States of America. Here is an example code snippet:

[ { "name": "Alabama", "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Birmingham%2C_Alabama_Skyline.jpg/1200px-Birmingham%2C_Alabama_Skyline.jpg", "description": "Sweet Home Alabama! Whether you're planning a weekend of golf or a seven-day beach getaway for the entire family, our Alabama Vacation & Events Guide as well as other brochures will help you find the perfect mix of activities, attractions and accommodations." }, { "name": "Alaska", "image": "https://www.smartertravel.com/uploads/2017/02/Alaska-Landscape.jpg", "description": "It can be overwhelming to plan a trip to Alaska. What are the best spots to see bears or moose or beautiful sunsets? Do you want to spend a lot of time in one area exploring the wilderness and mountains or make those side excursions while visiting Alaska’s diverse cities? Because Alaska is so big, it’s divided into 5 regions—start your planning by learning about these different locations." },

Next we are going to add a folder in the api called Models which will hold classes that have the same name and type of data as their database counterparts. We are going to use the Hotel class as an example. Here are the properties of the Hotel class, note that these fields have the same name and data type as in the database table.

private int Id; private string name; private int suitePrice; private int twoBedPrice; private int singleBedPrice;

Here are the constructors of the Hotel class:

public Hotel() { } public Hotel(int id, string name,int suite, int twoBed, int singleBed) { Id = id; this.name = name; suitePrice = suite; twoBedPrice = twoBed; singleBedPrice = singleBed; }

Also make sure that you create a property for each field, here is an example of a property:

public int ID { get { return Id; } set { Id = value; } }

Now create classes that correspond to the database tables like as shown above. Note that if the database as a DateTime column in it, in the class use a string data type to make sure that it is inputted correctly, do not worry about data validation because in the website we will make sure that it is only possible to input a date by putting an input of type date. Now go back to the controller that you created earlier. Here is something to note, if you want to create a Get function of the api and you want to pass some data to the api, you should put this above the method:

[HttpGet("GetState/{stateID}")]

If you want to have a Post method use this:

[HttpPost("InsertFlightOrder")]

Home Page

First we are going to create a GetState function in the api that will return a state when given and stateID number. For this function we are going to read from the JSON file and Deserialize it, which will allow us to turn that JSON object into a State object:

public String GetState(int stateID) { List items = null; using (StreamReader r = new StreamReader("stateInfo.json")) { string json = r.ReadToEnd(); items = JsonConvert.DeserializeObject>(json); } temp = items[stateID]; string message = temp.Name + "|" + temp.Image + "|" + temp.Description; return message; }

Now we are going to create a function that will get something from the Flight Table based on the flightName. We are going to need the Connection.cs file which can be found in the required software section of this site. In that file make sure that the username and password at the topmost string is your accessnet username and database password along with the url. Now first create a new DBConnect object and create a string that will hold the SQL query. We will then create a Dataset obejct that will hold the data in the table. Next create a Flight object that will hold the flight that we are getting. Now if data is returned then get the data, at the end return it.

[HttpGet("GetFlight/{flightName}")] public Flight GetFlight(string flightName) { DBConnect db = new DBConnect(); String sql = "SELECT * FROM Flights WHERE FlightName='" + flightName + "'"; DataSet recordSet = db.GetDataSet(sql); Flight newFlight = new Flight(); if (recordSet.Tables[0].Rows.Count > 0) { DataRow record = recordSet.Tables[0].Rows[0]; newFlight.FlightName = record["FlightName"].ToString(); newFlight.EconomyPrice = int.Parse(record["Economy Class"].ToString()); newFlight.BusinessPrice = int.Parse(record["Business Class"].ToString()); newFlight.FirstPrice = int.Parse(record["First Class"].ToString()); } return newFlight; }

Now we are going to create a function that will get a row from the Hotel table from teh hotelName. We are going to do the same thing that we did in GetFlight method except that instead of returning a Hotel object we will be returning a Hotel object.

[HttpGet("GetHotel/{hotelName}")] public Hotel GetHotel(string hotelName) { DBConnect db = new DBConnect(); String sql = "SELECT * FROM Hotels WHERE HotelName='" + hotelName + "'"; DataSet recordSet = db.GetDataSet(sql); Hotel newHotel = new Hotel(); if (recordSet.Tables[0].Rows.Count > 0) { DataRow record = recordSet.Tables[0].Rows[0]; newHotel.ID = int.Parse(record["Id"].ToString()); newHotel.Name = record["HotelName"].ToString(); newHotel.SuiteBedPrice = int.Parse(record["SuitePrice"].ToString()); newHotel.TwoBedPrice = int.Parse(record["TwoBedPrice"].ToString()); newHotel.SingleBedPrice = int.Parse(record["SingleBedPrice"].ToString()); } return newHotel; }

Next we are going to create a function that will insert a Flight Order into the FlightOrder table in the database. This method will accept all of the FlightOrder object fields. First we are going to create a DBConnect and a String that will hold the SQL query. When you insert the info make sure to put ' ' around string types, you do not have to surround numerical values with those. We are then going to call DoUpdate from the DBConnect object and return the result. The reason that this is a string isntead of an int is so if we run into any errors it will spit out exactly what went wrong.

[HttpPost("InsertFlightOrder")] public string InsertFlightOrder(string origin, string destination, string company, string flightClass, int numSeats, string tripStart, string tripEnd, int cost) { DBConnect db = new DBConnect(); String sql = "INSERT INTO FlightOrder VALUES('" + origin + "','" + destination + "','" + company + "','" + flightClass + "'," + numSeats + ",'" + tripStart + "','" + tripEnd + "'," + cost + ")"; string result = db.DoUpdate(sql); return result; }

Next we are going to create a function that will get all of the rows from the FlightOrder database. We are going to do the same thing as the GetFlight except for instead of an if statement we are going to use a for loop that will get the row, insert it into a Flight object and insert it into a list. We are going to return that list at the end.

[HttpGet("GetAllFlightOrder")] public List GetAllFlightOrder() { DBConnect db = new DBConnect(); String sql = "SELECT * FROM FlightOrder"; DataSet recordSet = db.GetDataSet(sql); List newOrderList = new List (); for (int row = 0; row < recordSet.Tables[0].Rows.Count; row++) { FlightOrder newOrder = new FlightOrder(); DataRow record = recordSet.Tables[0].Rows[row]; newOrder.Origin = record["Origin"].ToString(); newOrder.Destination = record["Destination"].ToString(); newOrder.Company = record["Company"].ToString(); newOrder.FlightClass = record["FlightClass"].ToString(); newOrder.NumSeats = int.Parse(record["NumSeats"].ToString()); newOrder.TripStart = record["TripStart"].ToString(); newOrder.TripEnd = record["TripEnd"].ToString(); newOrder.Cost = int.Parse(record["Cost"].ToString()); newOrderList.Add(newOrder); } return newOrderList; }

Next we are going to create a function that purges all of the flight orders from the Flight Order table. To do this we just have the string with the sql query do a Delete

[HttpGet("PurgeFlightOrder")] public string DeleteAllFlightOrder() { DBConnect db = new DBConnect(); String sql = "DELETE FROM FlightOrder"; string result = db.DoUpdate(sql); return result; }

Next we are going to insert a hotel order into the HotelOrder table by creating a function that does that. We are going to do the exact same thing as we did for the InsertFlightOrder function except we will be accepting the fields of a HotelOrder object and inserting those into the table.

[HttpPost("InsertHotelOrder")] public string InsertHotelOrder(string destination, string hotelName, string roomType, string customerFirst, string customerLast, string customerEmail, string tripStart, string tripEnd, string pickedUp, string flightNum, string additionalRequests, int numRooms, int cost) { DBConnect db = new DBConnect(); String sql = "INSERT INTO HotelOrder VALUES('" + destination + "','" + hotelName + "','" + roomType + "','" + customerFirst + "','" + customerLast + "','" + customerEmail + "','" + tripStart + "','" + tripEnd + "','" + pickedUp + "','" + flightNum + "','" + additionalRequests + "'," + numRooms + "," + cost + ")"; string result = db.DoUpdate(sql); return result; }

Next we are going to create a GetAllHotelOrder function that gets all of the rows from the HotelOrder table. This is about the same code as the GetAllFlightOrder function.

[HttpGet("GetAllHotelOrder")] public List GetAllHotelOrder() { DBConnect db = new DBConnect(); String sql = "SELECT * FROM HotelOrder"; DataSet recordSet = db.GetDataSet(sql); List newOrderList = new List (); for (int row = 0; row < recordSet.Tables[0].Rows.Count; row++) { HotelOrder newOrder = new HotelOrder(); DataRow record = recordSet.Tables[0].Rows[0]; newOrder.Destination = record["Destination"].ToString(); newOrder.HotelName = record["HotelName"].ToString(); newOrder.RoomType = record["RoomType"].ToString(); newOrder.CustomerFirst = record["CustomerFirst"].ToString(); newOrder.CustomerLast = record["CustomerLast"].ToString(); newOrder.TripStart = record["TripStart"].ToString(); newOrder.TripEnd = record["TripEnd"].ToString(); newOrder.PickedUp = record["PickedUp"].ToString(); newOrder.FlightNum = record["FlightNum"].ToString(); newOrder.AdditionalRequests = record["AdditionalRequests"].ToString(); newOrder.NumRooms = int.Parse(record["NumRooms"].ToString()); newOrder.Cost = int.Parse(record["Cost"].ToString()); newOrderList.Add(newOrder); } return newOrderList; }

Next we are going to create the PurgeHotelOrder function which deletes all of the rows from the HotelOrder table. This is the same code as the PurgeFlightOrder function except it is the Hotel Order table.

[HttpGet("PurgeHotelOrder")] public string DeleteAllHotelOrder() { DBConnect db = new DBConnect(); String sql = "DELETE FROM HotelOrder"; string result = db.DoUpdate(sql); return result; }

Destinations Page

First we are going to link a few things to the Destination html page in the head tags.

Next we are going to create our nav bar which will contain the links for the home page and book a trip page. In the nav tags we are going to have an unordered list with list items that have an anchor tag in them.

After the nav bar we are going to put a few breaks in there and create our search bar. But first we have to create a div with a id of content that has another div inside of it with an id of state-toolbar. In that div we are going to have an input of type text with an id of search-text and a button with an id of search-button.

We are then going to create three empty divs. This is where we are going to put content in via JavaScript. The first div id is going to be state-list, the second div has an id of search-state-results, and the third div has an id of state-info. We are now going to go over the javascript file called Destinations.js. First we are going to create an array that contains the names of all 50 states in the United States of America. We are then going to crate the window.onload function. We are then going to create two variables called searchButton and searchText. The serachButton will tie back to the button on the html page with an id of search-button and searchText will also be tied back to the html page.

let searchButton = document.getElementById("search-button"); let searchText = document.getElementById("search-text");

We will then call the createPage function that we will go over now. The create page function will create a variable named startStatePage that will tie back to the div called state-list in the html page. This will then go through the stateName array retrieving each name and passing both the startStatePage variable and the name of the state to the createState function.

let startStatePage = document.getElementById("state-list"); for (let i = 0; i < stateNames.length; i++) { createState(startStatePage, stateNames[i]); }

In the createState function we essentially call the api, retrieve the image and set that long with dynamically creating the divs and name of the state to the master div.

function createState(stateDoc, stateName) { let masterDocument = stateDoc; let stateDiv = document.createElement("div"); stateDiv.className = "state-tile"; stateDiv.id = stateName + "-tile"; stateDiv.value = stateName; let stateImageDiv = document.createElement("div"); stateImageDiv.className = "state-img"; let stateImage = document.createElement("img"); let request = new XMLHttpRequest(); let stateIndex = stateNames.indexOf(stateDiv.value) request.open("GET", "https://localhost:44342/api/Destination/GetState/" + stateIndex); request.setRequestHeader("Content-Type", "application/json; charset=utf-8"); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) { let temp = (request.responseText).split('|'); stateImage.src = temp[1]; } }; request.send(); let stateTextDiv = document.createElement("div"); let stateText = document.createElement("p"); let stateAcutalText = document.createTextNode(stateName); stateText.appendChild(stateAcutalText); stateImageDiv.appendChild(stateImage); stateTextDiv.appendChild(stateText); stateDiv.appendChild(stateImageDiv); stateDiv.appendChild(stateTextDiv); masterDocument.appendChild(stateDiv); stateDiv.onclick = function () { parent.location = "http://localhost:1337/Booking.html"; } }

We are also going to create a clearStates function that clears all of the states off of the page.

let masterDoc = document.getElementById("search-state-results"); while (masterDoc.hasChildNodes()) { masterDoc.removeChild(masterDoc.firstChild); }

We will also have a search button click event in which we read in the value from the search textbox, call clearStateResults, and use a for loop that analyzes what is in the textbox and call the createState function.

searchButton.onclick = function () { let searchValue = searchText.value; let stateListSection = document.getElementById("state-list"); let stateSearchSection = document.getElementById("search-state-results"); stateListSection.style.display = "none"; clearStateResults(); for (let i = 0; i < stateNames.length; i++) { if (stateNames[i].indexOf(searchValue) == false) { createState(stateSearchSection, stateNames[i]); } } }

Hotel Page

For the hotel page, we are going to create a form that will include the following:
A drop down menu with a list of all the states, another drop down with a list of our partner hotels, and another one witht the type of room our client would like to reserve.
We then have our client fill out basic information, such as name, email, number of rooms, etc then we created a date type for arrival and departures to and from our hotel. Eventually, the form would look like this:

We also added three tab buttons that serve as the primary navigation between the different pages. Once our client fills out the form, he has the option to submit the form and send it to our checkout.

$("#add-to-cart").click(function () { let stringURL = "https://localhost:44342/api/Destination/InsertHotelOrder/" let numRooms = parseInt($("#numRooms").val());

The above code sends the following data to our Insert function in our API if we have the following:

let stateDestination = $("#state-select-destination").val(); let hotelName = $("#hotel-select").val(); let hotelType = $("#hotel-type-select").val(); let customerFirst = $("#firstName").val(); let customerLast = $("#lastName").val(); let customerEmail = $("#email").val(); let tripStart = $("#start").val(); let tripEnd = $("#end").val(); let pickedUp = $('input[name=picked-up]:checked').val(); let flightNum = $("#flightNumber").val(); let additionalRequests = $("#requests").val(); let hotelPrice = parseInt($("#hotel-price").val()); if (hotelName != "Please Select" || hotelTypeSelected != "Please Select") { let orderData = "destination=" + stateDestination + "&hotelName=" + hotelName + "&roomType=" + hotelType + "&customerFirst=" + customerFirst + "&customerLast=" + customerLast + "&customerEmail=" + customerEmail + "&tripStart=" + tripStart + "&tripEnd=" + tripEnd + "&pickedUp=" + pickedUp + "&flightNum=" + flightNum + "&additionalRequests=" + additionalRequests + "&numRooms=" + numRooms + "&cost=" + hotelPrice; $.ajax({ type: "POST", url: stringURL, contentType: "application/x-www-form-urlencoded", dataType: "json", data: orderData, success: alert("Your order was added to the cart"), error: function (data) { $("flight-price").val(data); } })

Otherwise, if the following statements don't work then our code will assume that some fields have not been filled out or have been left blank, thus provoking error messages. Once everything is filled out, we generate a price according to the destinations that are filled in our database. Here is an example of how we set up the prices.

[HttpGet("GetHotel/{hotelName}/{state}")] public Hotel GetHotel(string hotelName, string state) { DBConnect db = new DBConnect(); String sql = "SELECT * FROM Hotels WHERE HotelName='" + hotelName + "'AND State='" + state + "'"; DataSet recordSet = db.GetDataSet(sql); Hotel newHotel = new Hotel(); if (recordSet.Tables[0].Rows.Count > 0) { DataRow record = recordSet.Tables[0].Rows[0]; newHotel.ID = int.Parse(record["Id"].ToString()); newHotel.Name = record["HotelName"].ToString(); newHotel.State = record["State"].ToString(); newHotel.SuiteBedPrice = decimal.Parse(record["SuitePrice"].ToString()); newHotel.TwoBedPrice = decimal.Parse(record["TwoBedPrice"].ToString()); newHotel.SingleBedPrice = decimal.Parse(record["SingleBedPrice"].ToString()); } return newHotel; }

Flight Page

Our flight page was fairly similar to our hotel check out page. Here are some screenshots that include before and after pictures of form submissions. This shows that our API has properly received the data and that it is being sent to our local host

Checkout Page

If you've reached this part of our website, then congrats! You've successfully booked a flight or reserved a hotel room!
This is where we start getting information about your overall order. First we start by getting the API that get's the flight's order. In this case, we'll be using flight.

$.ajax({ type: "GET", url: "https://localhost:44342/api/Destination/GetAllFlightOrder", contentType: "application/json/; charset=utf-8", dataType: "json",

Once we get that API, we want to use javascript to display everything that's been displayed. We can do that with the following:

if (flightList.length != 0) { $("#flight-head").css("display", "inline"); for (let i = 0; i < flightList.length; i++) { let company = flightList[i].Company; let flightClass = flightList[i].FlightClass; let numSeats = flightList[i].NumSeats; let dateStartSplit = (flightList[i].TripStart).split("-"); let dateStart = (dateStartSplit[1] + "/" + dateStartSplit[2] + "/" + dateStartSplit[0]); let tripStart = dateStart; let dateEndSplit = (flightList[i].TripEnd).split("-"); let dateEnd = (dateEndSplit[1] + "/" + dateEndSplit[2] + "/" + dateEndSplit[0]); let tripEnd = dateEnd; let cost = "$" + flightList[i].Cost + "/per seat round trip"; let head = $("

").text(flightList[i].Origin + " To " + flightList[i].Destination); let companyText = $("

").text(company); let flightClassText = $("

").text(flightClass); let numSeatsText = $("

").text(numSeats); let tripStartText = $("

").text(tripStart); let tripEndText = $("

").text(tripEnd); let costText = $("

").text(cost); $("#flight-div").append(head,companyText, flightClassText, numSeatsText, tripStartText, tripEndText, costText); }

If our statements are not fulfilled, then nothing would be displayed. If everything works properly, then our database sends all the information that the client has filled out.

In Summary

JavaScript’s rising popularity has brought with it a lot of changes, and the face of web development today is dramatically different. In summary, Node is a great runtime environment for running code from a server, which can significantly speed up the loading of the page and is very light to use as well.
Node.js is primarily used for non-blocking, event-driven servers, due to its single-threaded nature. It is also used for traditional web sites and back-end API services, such as the ones we've leanred in class. Node.js operates on a single-thread, allowing it to support tens of thousands of concurrent connections held in an event loop.

References